# -*- coding: utf-8 -*-
import re
import pandas as pd
import json

from get_cwe_root import get_cwe_root

from JULIET import JULIET
from PERFORMANCE import PERFORMANCE

class SEMGREP:
    '''对 semgrep 的 result.json 进行分析'''
    def __init__(self) -> None:
        # semgrep 结果 json 文件路径
        self.semgrep_result_json_path='../scan_data/semgrep/semgrep-scan-result.json'
        # 根据 semgrep_result_json_path 来生成的，保存了 semgrep 的分析结果
        self.result=[]
        # 生成 result 数据
        self.analyze_result=[]
        # 用于获取 cwe 编号之间继承关系的对象
        self.cwe_root=get_cwe_root()
        # juliet 对象，里面包括了 juliet 数据集的预期数据及一些可以调用的方法
        self.juliet=JULIET()
        self.get_result_from_json_file()
        self.get_analyze_result()
        # # 性能分析
        # time_log_path='/home/pudding/work/temp/result/sast_result/sast_result/semgrep/3/semgrep_time.log'
        # top_log_path='/home/pudding/work/temp/result/sast_result/sast_result/semgrep/3/semgrep_top.log'
        # iotop_log_path='/home/pudding/work/temp/result/sast_result/sast_result/semgrep/3/semgrep_iotop.log'
        # top_command='semgrep'
        # iotop_command='semgrep run --bufferoverrun --biabduction --pulse -- make -j6 -B'
        # performance_save_path='semgrep_performance.xlsx'
        # performance=PERFORMANCE(time_log_path,top_log_path,iotop_log_path,top_command,iotop_command,performance_save_path)

    def get_result_from_json_file(self):
        '''将 semgrep 分析出的 json 结果解析到 result 对象中'''
        with open(self.semgrep_result_json_path,'r') as f:
            semgrep_json_file_content=json.loads(f.read())
        for item in semgrep_json_file_content['results']:
            cweid = item['extra']['metadata']['cwe'][0]
            # 把CWE-020的格式改成CWE-20
            cweid = 'CWE-'+str(int(re.findall(r'CWE-(\d+)',cweid)[0]))            
            one_result={
                'cweid':cweid,
                'line':str(item['start']['line']),
                'path':item['path']
            }
            self.result.append(one_result)

    def get_analyze_result(self):
        '''对结果进行分析'''
        # juliet 测试用例的总数
        juliet_testcases_number=0
        for item in self.juliet.result.values():
            juliet_testcases_number+=len(item)
        # semgrep 重复报告相同的 juliet 测试用例数量
        semgrep_repeat_number=0
        # semgrep 的结果总数
        semgrep_result_number=len(self.result)
        # 匹配成功的用例数量
        success_report_number=0
        # 匹配成功的 juliet 的测试用例列表,避免同一个测试用例被多次算作 success_report_number 里
        success_juliet_testcase_list=[]
        # 遍历 semgrep 的 result
        for item in self.result:
            # 根据文件名去 juliet 找对应的测试用例
            file_name=item['path'].split('/')[-1]
            juliet_testcase=self.juliet.get_testcase_by_file_name(file_name)
            # 如果找不到对应的测试用例就 continue
            if not juliet_testcase:
                continue
            # 获取 juliet 的测试用例对应的 cweid
            juliet_testcase_cweid=self.juliet.get_testcase_cweid(juliet_testcase)
            # 获取 semgrep 的 cweid 与 juliet 的 cweid 之间的继承关系
            relations=self.cwe_root.get_relations(item['cweid'],juliet_testcase_cweid)
            # semgrep 的 cweid 为 juliet 的祖辈或者相等或子辈
            if relations in ['ancestor','equal','descendant']:
                # 行数与 juliet 测试用例的行数匹配
                if self.juliet.if_mate_line(item['line'],file_name,juliet_testcase):
                    # 如果 juliet 的该测试用例没有被统计过,算一次成功的报告,成功报告数量加一，并且该测试用例记录下来
                    if juliet_testcase not in success_juliet_testcase_list:
                        success_report_number+=1
                        success_juliet_testcase_list.append(juliet_testcase)
                    # 如果该测试用例被统计过,记录到 semgrep_repeat_number
                    else:
                        semgrep_repeat_number+=1

        # 召回率/准确率：正确报告数与测试用例中用例总数的比值
        rcr=success_report_number/juliet_testcases_number
        # 误报率：错误报告数占工具所有报告总数的比值，错误报告数=semgrep总报告数-semgrep成功报告数-semgrep重复报告数
        fpr=(semgrep_result_number-success_report_number-semgrep_repeat_number)/semgrep_result_number
        excel_res={
            'juliet_testcases_number':[juliet_testcases_number],
            'semgrep_result_number':[semgrep_result_number],
            'success_report_number':[success_report_number],
            'rcr':[rcr],
            'fpr':[fpr],
        }
        df=pd.DataFrame(excel_res)
        df.to_excel('./analyze_result/semgrep_analyze_result.xlsx', sheet_name='main')